package main

import (
	"log"
	"sync"
	"time"
)

// 使用 sync.Mutex 实现根据条件轮询等待

// 缺点：轮询的开销较大，轮询的间隔会影响检查的及时性
type signal struct{}

var ready bool

func worker(i int) {
	log.Printf("worker %d is working...", i)
	time.Sleep(1 * time.Second)
	log.Printf("worker %d works done", i)
}

func spawnGroup(f func(i int), num int, mu *sync.Mutex) <-chan signal {
	c := make(chan signal)
	var wg sync.WaitGroup

	for i := 0; i < num; i++ {
		wg.Add(1)

		go func(n int) {
			for {
				mu.Lock()

				if !ready {
					mu.Unlock()
					time.Sleep(100 * time.Millisecond)

					continue
				}

				mu.Unlock()

				f(n)

				wg.Done()

				return
			}

		}(i + 1)
	}

	go func() {
		wg.Wait()
		c <- signal(struct{}{})
	}()

	return c
}

func main() {
	log.Println("a group of worker start to work...")

	mu := &sync.Mutex{}

	c := spawnGroup(worker, 5, mu)

	time.Sleep(3 * time.Second)

	mu.Lock()
	ready = true
	mu.Unlock()

	<-c

	log.Println("program exit")

}
